home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / ast_comp / gopher.lha / gopher1.01 / gopherd / gopherd.c < prev    next >
C/C++ Source or Header  |  1992-06-24  |  36KB  |  1,588 lines

  1. /* Originally derived from an 
  2.  * Example of server using TCP protocol
  3.  * pp 284-5 Stevens UNIX Network Programming
  4.  */
  5.  
  6.  
  7. #include "gopherd.h"
  8. void LOGGopher();
  9.  
  10. static    int    uid = -2;        /* use root by default */
  11.  
  12.  
  13. #ifdef LOADRESTRICT
  14.  
  15. #ifndef MAXLOAD
  16. #define MAXLOAD 10.0
  17. #endif
  18. double atof();
  19. double maxload = MAXLOAD;
  20. double sysload = 0.0;
  21. #include <nlist.h>
  22. #include <kvm.h>
  23. int nproc;
  24. long avenrun[3];
  25. kvm_t * kd;
  26. char prog[1024];
  27. struct   nlist nl[] = {
  28.     {"_avenrun" },  /* SunOS 4.1.1, your milage may vary... */
  29. #define X_AVENRUN 0
  30.     {""},
  31. };
  32.  
  33. #endif /*LOADRESTRICT */
  34.  
  35.  
  36. /*
  37.  * This routine finds out the hostname of the server machine.
  38.  * It uses a couple of methods to find the fully qualified 
  39.  * Domain name
  40.  */
  41.  
  42. char *
  43. GetDNSname(backupdomain)
  44.   char *backupdomain;
  45. {
  46.      static char DNSname[MAXHOSTNAMELEN];
  47.      struct hostent *hp;
  48.  
  49.  
  50.      /* Work out our fully-qualified name, for later use */
  51.      
  52.      if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
  53.       fprintf(stderr, "Cannot determine the name of this host\n");
  54.       exit(-1);
  55.  
  56.      }
  57.  
  58.      /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
  59.      hp = gethostbyname( DNSname);
  60.  
  61.      /*
  62.       ** If we got something, and the name is longer than hostname, then
  63.       ** assume that it must the the fully-qualified hostname
  64.       */
  65.      if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) ) 
  66.       strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
  67.      else
  68.       strcat(DNSname, backupdomain);
  69.  
  70.      return(DNSname);
  71. }
  72.  
  73.  
  74. /*
  75.  * Tries to figure out what the currently connected port is.
  76.  * 
  77.  * If it's a socket then it will return the port of the socket, 
  78.  * if it isn't a socket then it returns -1.
  79.  */
  80.  
  81. int GetPort(fd)
  82.   int fd;
  83. {
  84.      struct sockaddr_in serv_addr;
  85.  
  86.      int length = sizeof(serv_addr);
  87.      
  88.      /** Try to figure out the port we're running on. **/
  89.      
  90.      if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
  91.       return(ntohs(serv_addr.sin_port));
  92.      else
  93.       return(-1);
  94.  
  95. }
  96.  
  97.  
  98.  
  99. void
  100. main(argc, argv)
  101.   int     argc;
  102.   char     *argv[];
  103. {
  104.      int sockfd;
  105.      int newsockfd;
  106.      int clilen;
  107.      int childpid;
  108.      int i;
  109.  
  110.      struct sockaddr_in serv_addr;
  111.      struct sockaddr_in cli_addr;
  112.  
  113.      /*** for getopt processing ***/
  114.      int c;
  115.      extern char *optarg;
  116.      extern int optind;
  117.      int errflag =0;
  118.  
  119.  
  120.      pname = argv[0];
  121.      strcpy(Data_Dir, DATA_DIRECTORY);
  122.      err_init();    /* openlog() early - before we chroot() of course */
  123.  
  124.      /*** Check argv[0], see if we're running as gopherls, etc. ***/
  125.  
  126.      RunServer = RunLS = RunIndex = FALSE;
  127.  
  128.      if (strstr(argv[0], "gopherls") != NULL) {
  129.       RunLS = TRUE;
  130.      } else if (strstr(argv[0], "gindexd") != NULL) {
  131.       RunIndex = TRUE;
  132.       dochroot = FALSE;
  133.      } else 
  134.       RunServer = TRUE;  /** Run the server by default **/
  135.  
  136.  
  137.      while ((c = getopt(argc, argv, "mCDIcL:l:s:u:U:")) != -1)
  138.       switch (c) {
  139.       case 'D':
  140.            DEBUG = TRUE;
  141.            break;
  142.  
  143.       case 'I':
  144.            RunFromInetd = TRUE;
  145.            break;
  146.  
  147.       case 'C':
  148.            Caching = FALSE;
  149.            break;
  150.  
  151.       case 'm':
  152.         if (RunIndex)
  153.             MacIndex = TRUE;
  154.         break;
  155.  
  156.       case 'c':
  157.            dochroot = FALSE;
  158.            if (!RunFromInetd) {
  159.             printf("Not using chroot() - be careful\n");
  160.             if ( getuid() == 0 || geteuid() == 0 )
  161.              printf("You should run without root perms\n");
  162.            }
  163.            break;
  164.  
  165.       case 'L':  /** Load average at which to restrict usage **/
  166. #ifdef LOADRESTRICT
  167.            maxload = atof(optarg);
  168. #endif
  169.            break;
  170.  
  171.       case 'l':  /** logfile name **/
  172.            if (*optarg == '/')
  173.             strcpy(LOGFile, optarg);
  174.            else {
  175.             getwd(LOGFile);
  176.             strcat(LOGFile, "/");
  177.             strcat(LOGFile, optarg);
  178.            }
  179.            break;
  180.            
  181.       case 's': /** security file name **/
  182.            if (*optarg == '/')
  183.             strcpy(SecurityFile, optarg);
  184.            else {
  185.             getwd(SecurityFile);
  186.             strcat(SecurityFile, "/");
  187.             strcat(SecurityFile, optarg);
  188.            }
  189.            break;
  190.  
  191.       case 'u':
  192.            {
  193.             struct passwd *pw = getpwnam( optarg );
  194.             if ( !pw ) {
  195.              fprintf(stderr,
  196.                   "Could not find user '%s' in passwd file\n",
  197.                   optarg);
  198.              errflag++;
  199.             } else {
  200.              uid = pw->pw_uid;
  201.              if (!RunFromInetd) {
  202.                   printf("Running as user '%s' (%d)\n",
  203.                    optarg, uid);
  204.              }
  205.             }
  206.            }
  207.            break;
  208.  
  209.       case 'U':    /* set uid to use */
  210.            uid = atoi( optarg );
  211.            if (!RunFromInetd) {
  212.             printf("Running using uid %d\n", uid);
  213.            }
  214.            break;
  215.       case '?':
  216.       case 'h':
  217.            errflag++;
  218.            break;
  219.       }
  220.  
  221.  
  222.      if (errflag) {
  223.       fprintf(stderr, "Usage: %s [-CDIc] [-u userid] [-U uid] [-s securityfile] [-l logfile] <datadirectory> <port>\n", argv[0]);
  224.       fprintf(stderr, "   -C  turns caching off\n");
  225.       fprintf(stderr, "   -D  enables copious debugging info\n");
  226.       fprintf(stderr, "   -I  enable \"inetd\" mode\n");
  227.       fprintf(stderr, "   -c  disable chroot(), use secure open routines instead\n");
  228.       fprintf(stderr, "   -u  specifies the username for use with -c\n");
  229.       fprintf(stderr, "   -U  specifies the UID for use with -c\n");
  230.       fprintf(stderr, "   -s  specifies the name of a security file\n");
  231.       fprintf(stderr, "   -l  specifies the name of a logfile\n");
  232.           
  233.       exit(-1);
  234.      }
  235.  
  236.      if (uid == -2) 
  237.       uid = getuid();  /** Run as current user... **/
  238.  
  239.      if ( uid == 0 && !RunFromInetd )
  240.       printf("Hope you know what you're doing ...\n");
  241.  
  242.  
  243.      if (optind < argc) {
  244.       strcpy(Data_Dir, argv[optind]);
  245.       optind++;
  246.      } else if (RunLS)
  247.       strcpy(Data_Dir, "/");
  248.  
  249.      if (optind < argc) {
  250.       GopherPort = atoi(argv[optind]);
  251.       optind++;
  252.      }
  253.  
  254.      if (RunLS) {
  255.       Zehostname ="";
  256.       Caching = FALSE;
  257.  
  258.       fflush(stdout);
  259.       uchdir(Data_Dir);
  260.  
  261.       listdir(0, "/");
  262.       exit(0);
  263.      }
  264.  
  265.      if (!RunFromInetd) {
  266.       printf("Data directory is %s\n", Data_Dir);
  267.       printf("Port is %d\n", GopherPort);
  268.      }
  269.  
  270.      if (*LOGFile != '\0' && !RunFromInetd)
  271.       printf("Logging to File %s\n", LOGFile);
  272.  
  273.      if (*SecurityFile != '\0' && !RunFromInetd)
  274.       printf("Using Security file %s\n", SecurityFile);
  275.  
  276.      /*
  277.       * Would like to setuid() here, but have to wait until after the
  278.       * bind() in case we're going to be running on a privileged port.
  279.       */
  280.  
  281.      if (uchdir(Data_Dir)) {
  282.       if (!RunIndex) {
  283.            fprintf(stderr, "Cannot change to data directory!! %s \n",Data_Dir);
  284.            exit(-1);
  285.       }
  286.      }
  287.  
  288.      if (dochroot && getuid() != 0) {
  289.       fprintf(stderr, "Gopherd uses the privileged call chroot().  Please become root.\n");
  290.       exit(-1);
  291.      }
  292.  
  293.  
  294.      /** Open up the SecurityFile
  295.          **Warning!** we have to do this over because the daemon_start
  296.          function closes all fd's
  297.  
  298.      This part just checks to see if the file exists...
  299.       **/
  300.  
  301.  
  302.      if (*SecurityFile != '\0') {
  303.       SECFileHandle = ufopen(SecurityFile, "r");
  304.  
  305.       if (SECFileHandle == NULL) {
  306.            printf("Can't open the security file: %s\n", SecurityFile);
  307.            exit(-1);
  308.       }
  309.       fclose(SECFileHandle);
  310.      }
  311.      
  312.  
  313. #ifdef LOADRESTRICT
  314.  
  315.      if(RunFromInetd) {
  316.       if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, prog)) == NULL) 
  317.            exit(-1);
  318.       if (kvm_nlist(kd, nl) != 0) 
  319.            exit(-1);
  320.       if(nl[X_AVENRUN].n_type == 0) 
  321.            exit(-1);
  322.       if(kvm_read(kd,nl[X_AVENRUN].n_value,avenrun,sizeof avenrun) 
  323.          != sizeof avenrun) 
  324.            exit(-1);
  325.       if((sysload = (((double) avenrun[2]) / FSCALE)) > maxload) {
  326.            printf("- System Load exceeded (%4.2f > %4.2f). ",sysload,maxload);
  327.            printf("Please Retry Request later.\r\n.\r\n");
  328.            exit(1);
  329.       }
  330.      }
  331. #endif /*LOADRESTRICT*/     
  332.  
  333.  
  334.  
  335.      if (DEBUG == FALSE && RunFromInetd==FALSE)
  336.       daemon_start(0);
  337.  
  338.  
  339.      /*** Hmmm, does this look familiar? :-) ***/
  340.  
  341.  
  342.      if (*SecurityFile != '\0') {
  343.       SECFileHandle = ufopen(SecurityFile, "r");
  344.  
  345.       if (SECFileHandle == NULL) {
  346.            printf("Can't open the security file: %s\n", SecurityFile);
  347.            exit(-1);
  348.       }
  349.      }
  350.  
  351.      err_init();    /* does this look familiar too?? :-) */
  352.  
  353.      /** Ask the system what host we're running on **/
  354.  
  355.      Zehostname = GetDNSname(DOMAIN_NAME);
  356.  
  357.  
  358.      if (RunFromInetd) {
  359.       /** Ask the system which port we're running on **/
  360.       int newport=0;
  361.       if ((newport =GetPort(0)) !=0)
  362.            GopherPort=newport;
  363.  
  364.       /*** Do the stuff for inetd ***/
  365.  
  366.       while(do_command(0)!=0);    /* process the request */
  367.       exit(0);
  368.      }
  369.  
  370.      /** Open a TCP socket (an internet stream socket **/
  371.      
  372.      if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  373.       err_dump("server: can't open stream socket");
  374.      
  375.      /** Bind our local address so that the client can send to us **/
  376.      
  377.      bzero((char *) &serv_addr, sizeof(serv_addr));
  378.      serv_addr.sin_family         = AF_INET;
  379.      serv_addr.sin_addr.s_addr     = htonl(INADDR_ANY);
  380.      serv_addr.sin_port        = htons(GopherPort);
  381.      
  382.      if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
  383.       err_dump("server: can't bind local address");
  384.      
  385.      /* have to setuid() here, in case we're using a privileged port */
  386.      if ( setuid(uid) != 0 )
  387.       err_sys("Cannot setuid(%d): ",uid);
  388.  
  389.      listen(sockfd, 5);
  390.      
  391.      for ( ; ; ) {
  392.       /*
  393.        * Wait for a connection from a client process.
  394.        * This is an example of a concurrent server.
  395.        */
  396.       
  397.       clilen = sizeof(cli_addr);
  398.       newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
  399.                  &clilen);
  400.  
  401.       /*** weird.. with this thing here our gethostaddrs work. 
  402.             without it, it fails..... why?
  403.            ***/
  404.       
  405.       if (newsockfd < 0)
  406.            err_dump("server: accept error");
  407.       
  408.       if ( (childpid = fork()) < 0)
  409.            err_dump("server: fork error");
  410.       
  411.       else if (childpid == 0) {    /* Child process */
  412.            close(sockfd);        /* close original socket */
  413.  
  414.            while(do_command(newsockfd)!=0);    /* process the request */
  415.            exit(0);
  416.       }
  417.       /** clean up any zombie children **/
  418.       sig_child();
  419.  
  420.       close(newsockfd);         /* parent process */
  421.      }
  422. }
  423.  
  424.  
  425. /*
  426.  *
  427.  *  Code stolen from nntp.....
  428.  *
  429.  * inet_netnames -- return the network, subnet, and host names of
  430.  * our peer process for the Internet domain.
  431.  *
  432.  *      Parameters:     "sock" is our socket, which we don't need.
  433.  *                      "sin" is a pointer to the result of
  434.  *                      a getpeername() call.
  435.  *                      "host_name"
  436.  *                      is filled in by this routine with the
  437.  *                      corresponding ASCII names of our peer.
  438.  *      Returns:        Nothing.
  439.  *      Side effects:   None.
  440.  */
  441.  
  442. inet_netnames(sock, sin, host_name)
  443.         int                     sock;
  444.         struct sockaddr_in      *sin;
  445.         char                    *host_name;
  446. {
  447.         u_long                  net_addr;
  448.         struct hostent          *hp;
  449.         struct netent           *np;
  450.  
  451.         net_addr = inet_netof(sin->sin_addr);   /* net_addr in host order */
  452.         np = getnetbyaddr(net_addr, AF_INET);
  453.  
  454.         hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
  455.                 sizeof (sin->sin_addr.s_addr), AF_INET);
  456.  
  457.         if (hp != NULL)
  458.                 (void) strcpy(host_name, hp->h_name);
  459.         else
  460.                 (void) strcpy(host_name, inet_ntoa(sin->sin_addr));
  461. }
  462.  
  463.  
  464.  
  465. /*
  466.  * This finds the current peer and the time and  jams it into the
  467.  * logfile (if any) and adds the message at the end
  468.  */
  469.  
  470. void
  471. LOGGopher(sockfd, message)
  472.   int sockfd;
  473.   char *message;
  474. {
  475.      struct sockaddr sa;
  476.      int             length;
  477.      static char     host_name[256];
  478.      time_t          Now;
  479.      char            *cp;
  480.                      /* cp + ' ' + host_name + ' : ' + MAXLINE + '\n' + '\0' */
  481.      char            buf[286+MAXLINE];
  482.      struct flock    lock;
  483.    
  484.  
  485.      host_name[0] = '\0';
  486.  
  487.      if (LOGFileDesc != -1) {
  488.       
  489.       if (sockfd > -1) {
  490.            length = sizeof (sa);
  491.            getpeername(sockfd, &sa, &length);
  492.            inet_netnames(sockfd, &sa, host_name);
  493.       }
  494.  
  495.       lock.l_type = F_WRLCK;
  496.       lock.l_whence = SEEK_SET;
  497.           lock.l_start = 0L;
  498.           lock.l_len = 0L;
  499.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  500.  
  501.       time(&Now);         /* Include this in the lock to make sure */
  502.       cp = ctime(&Now);   /*  log entries are chronological */
  503.       ZapCRLF(cp);
  504.  
  505.           /* someone else may have written to the file since we opened it */
  506.           lseek(LOGFileDesc, 0L, SEEK_END);
  507.   
  508.           sprintf(buf, "%s %d %s : %s\n", cp, getpid(), host_name, message);
  509.           write(LOGFileDesc, buf, strlen(buf));
  510.           
  511.           /* unlock the file */
  512.           lock.l_type = F_UNLCK;
  513.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  514.       
  515.       if (DEBUG)
  516.            printf("%s %d %s : %s\n", cp, getpid(), host_name, message);
  517.       
  518.      }
  519. }
  520.  
  521.  
  522. process_mailfile(sockfd, Mailfname)
  523.   int sockfd;
  524.   char *Mailfname;
  525. {
  526.      FILE *Mailfile;
  527.      char Zeline[MAXLINE];
  528.      char outputline[MAXLINE];
  529.      char Title[MAXLINE];
  530.      long Startbyte=0, Endbyte=0, Bytecount=0;
  531.      boolean flagged = 0;
  532.  
  533.      Mailfile = rfopen(Mailfname, "r");
  534.  
  535.      if (Mailfile == NULL) {
  536.       Abortoutput(sockfd, "Cannot access file");
  537.       return;
  538.      }
  539.  
  540.      while (fgets(Zeline, MAXLINE, Mailfile) != NULL) {
  541.       if (strncmp(Zeline, "Subject: ", 9)==0 && (!flagged)) {
  542.            flagged =1;
  543.            strcpy(Title, Zeline + 9);
  544.            ZapCRLF(Title);
  545.            if (DEBUG)
  546.             fprintf(stderr, "Found title %s", Title);
  547.       }
  548.       
  549.       if (is_mail_from_line(Zeline)==0) {
  550.            Endbyte = Bytecount;
  551.            flagged =0;
  552.  
  553.            if (Endbyte != 0) {
  554.             sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  555.                 Title, Startbyte, Bytecount, Mailfname,
  556.                 Zehostname, GopherPort);
  557.             if (writestring(sockfd, outputline) < 0)
  558.              LOGGopher(sockfd, "Client went away"), exit(-1);
  559.             Startbyte=Bytecount;
  560.             *Title = '\0';
  561.            }
  562.       }
  563.  
  564.       Bytecount += strlen(Zeline);
  565.      }
  566.  
  567.      if (*Title != '\0') {
  568.       sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  569.           Title, Startbyte, Bytecount, Mailfname, 
  570.           Zehostname, GopherPort);
  571.       if (writestring(sockfd, outputline)<0)
  572.            LOGGopher(sockfd, "Client went away"),exit(-1);
  573.      }      
  574.  
  575.  
  576.      if (writestring(sockfd, ".\r\n")<0)
  577.       LOGGopher(sockfd, "Client went away"),exit(-1);
  578. }
  579.  
  580.  
  581.  
  582. boolean
  583. Can_Read(sockfd)
  584.   int sockfd;
  585. {
  586.      struct sockaddr sa;
  587.      int             length;
  588.      char            host_name[256];
  589.      char *cp;
  590.      boolean         MatchReturn;
  591.      char            inputline[MAXLINE];
  592.  
  593.      if (*SecurityFile == '\0')
  594.       return(TRUE);
  595.  
  596.      length = sizeof (sa);
  597.      getpeername(sockfd, &sa, &length);
  598.      inet_netnames(sockfd, &sa, host_name);
  599.  
  600.      fseek(SECFileHandle, 0, 0);  /** Go to beginning of Security File **/
  601.      
  602.      while (fgets(inputline, MAXLINE, SECFileHandle) != NULL) {
  603.       ZapCRLF(inputline);
  604.  
  605.       MatchReturn = TRUE;
  606.       cp = inputline;
  607.  
  608.       if (*cp == '!') {
  609.            MatchReturn = FALSE;
  610.            cp++;
  611.       }
  612.       
  613.       if (isdigit(*cp)) {
  614.            /** Internet address x.x.x.x ..***/
  615.            /** Check for a match from the beginning **/
  616.            if (strstr(host_name,cp) == host_name)
  617.             return(MatchReturn);
  618.             
  619.       }
  620.       
  621.       else if (*cp == '*') {
  622.            return(MatchReturn);
  623.       }
  624.  
  625.       else if (*cp != '#') {
  626.            /*** Not a comment, must be a host name **/
  627.            if ((strstr(host_name, cp) + strlen(cp)) == (host_name + strlen(host_name))) {
  628.             return(MatchReturn);
  629.            }
  630.       }
  631.      }
  632.  
  633.      /*** Hmmm, didn't find a match...  Let em have it***/
  634.       
  635.      return(TRUE);
  636. }
  637.  
  638.  
  639.  
  640. int
  641. do_command(sockfd)
  642.   int sockfd;
  643. {
  644.      char inputline[MAXLINE];
  645.      int length;        /* Length of the command line */
  646.      char logline[MAXLINE];
  647.      char *selstr;
  648.  
  649.      /*** Reopen the security file ***/
  650.  
  651.      if (*SecurityFile != '\0') {
  652.       SECFileHandle = ufopen(SecurityFile, "r");
  653.  
  654.       if (SECFileHandle == NULL) {
  655.            LOGGopher(sockfd, "Security File dissappeared!");
  656.            exit(-1);
  657.       }
  658.      }
  659.      
  660.      /*** Reopen the log file ***/
  661.  
  662.      if (LOGFile[0] != '\0') {
  663.       LOGFileDesc = uopen(LOGFile, O_WRONLY | O_APPEND |O_CREAT, 0755);
  664.       
  665.       if (LOGFileDesc == -1) {
  666.            printf("Can't open the logfile: %s\n", LOGFile);
  667.            exit(-1);
  668.       }
  669.      }
  670.  
  671.  
  672.      /** Change our root directory **/
  673.      
  674.      if ( dochroot ) {
  675.       if (chroot(Data_Dir)) {
  676.            Abortoutput(sockfd, "Data_Dir dissappeared!");
  677.            exit(-1);
  678.       }
  679.       uchdir("/");    /* needed after chroot */
  680.      }
  681.  
  682.      if (setuid(uid)) {
  683.       LOGGopher(sockfd, "Can't set UID!");
  684.       Abortoutput(sockfd, "Can't set UID!");
  685.       exit(-1);
  686.      }
  687.       
  688.      length = readline(sockfd, inputline, MAXLINE); /** Get the line **/
  689.  
  690.      if (length <= 0) {
  691.       close(sockfd);
  692.       err_quit("getcommand: readline error");
  693.      }
  694.      
  695.      ZapCRLF(inputline);
  696.  
  697.  
  698.      /*
  699.       * Decide if we're an HTML server or not...
  700.       */
  701.  
  702.      if (strncmp(inputline, "GET /", 5) == 0) {
  703.       char *htmlcpin;
  704.       char *htmlcpout;
  705.  
  706.       UsingHTML = TRUE;
  707.       selstr = inputline+5;
  708.  
  709.       /** Convert the hex things back to text... ***/
  710.       Fromhexstr(selstr, selstr);
  711.  
  712.      } else
  713.       selstr = inputline;
  714.  
  715.      if (RunIndex) {
  716.       /*** Run like the old gindexd thing. ***/
  717.       
  718.       char tempstr[512];
  719.       
  720.       uchdir("/");
  721.  
  722.       strcpy(tempstr, Data_Dir);
  723.       strcat(tempstr, "\t");
  724.       if (*selstr == '\t')
  725.            strcat(tempstr, selstr+1);
  726.       else
  727.            strcat(tempstr, selstr);
  728.  
  729.       strcpy(Data_Dir, "/");
  730.       
  731.       if (DEBUG)
  732.            writestring(sockfd, tempstr);
  733.  
  734.  
  735.       Do_IndexTrans(sockfd, tempstr);
  736.       return(0);
  737.      }
  738.  
  739.      /*** With the funky new capability system we can just check the
  740.           first letter, end decide what the object refers to. ***/
  741.  
  742.      switch (*selstr) {
  743.      case '\0':
  744.      case '\t':
  745.  
  746.       /*** The null capability, so it's not a file, probably wants
  747.            to talk to a directory server ***/
  748.  
  749.       /*** we'll just do a "list" of the root directory, with no user
  750.            capability.  ***/
  751.  
  752.       listdir(sockfd, "/");
  753.       LOGGopher(sockfd, "Root Connection");
  754.       break;
  755.  
  756.      case 'h':
  757.       /*** A raw html file ***/
  758.       /*** Turn off html'ing and just dump the file ***/
  759.       UsingHTML = FALSE;
  760.  
  761.      case '0':
  762.       /*** It's a generic file capability ***/
  763.       printfile(sockfd, selstr+1, 0, -1);
  764.  
  765.       /*** Log it ***/
  766.       strcpy(logline, "retrieved file ");
  767.       strcat(logline, selstr+1);
  768.       LOGGopher(sockfd, logline);
  769.       break;
  770.  
  771.      case '1':
  772.       /*** It's a directory capability ***/
  773.       listdir(sockfd, selstr+1);
  774.  
  775.       /** Log it **/
  776.       strcpy(logline, "retrieved directory ");
  777.       strcat(logline, selstr+1);
  778.       LOGGopher(sockfd, logline);
  779.  
  780.       break;
  781.  
  782.      case '7':
  783.       /*** It's an index capability ***/
  784.       Do_IndexTrans(sockfd, selstr+1);
  785.  
  786.       break;
  787.  
  788.      case '9':
  789.       /*** It's a binary thingie... ***/
  790.       /*** Okay, it's not a sound, but what the heck.... ***/
  791.       echosound(sockfd, selstr+1);
  792.       
  793.       /* Log it */
  794.       strcpy(logline, "retrieved binary ");
  795.       strcat(logline, selstr+1);
  796.       LOGGopher(sockfd, logline);
  797.       break;
  798.  
  799.      case 's':
  800.       /*** It's a sound capability ***/
  801.       echosound(sockfd, selstr+1);
  802.  
  803.       /* Log it */
  804.       strcpy(logline, "retrieved sound ");
  805.       strcat(logline, selstr+1);
  806.       LOGGopher(sockfd, logline);
  807.       break;
  808.  
  809.      case 'm':
  810.       /*** This is an internal identifier ***/
  811.       /*** The m paired with an Objtype of 1 makes a mail spool file
  812.            into a directory.
  813.       ***/
  814.  
  815.       process_mailfile(sockfd, selstr + 1);
  816.  
  817.       /** Log it **/
  818.       strcpy(logline, "retrieved maildir ");
  819.       strcat(logline, selstr+1);
  820.       LOGGopher(sockfd, logline);
  821.  
  822.       break;
  823.  
  824.      case 'R':
  825.       /*** This is an internal identifier ***/
  826.       /*** The R defines a range  ****/
  827.       /*** The format is R<startbyte>-<endbyte>-<filename> **/
  828.      {
  829.       int startbyte, endbyte;
  830.       char *cp, *oldcp;
  831.  
  832.       cp = strchr(selstr+1, '-');
  833.       
  834.       if (cp == NULL) {
  835.            Abortoutput(sockfd, "Range specifier error");
  836.            break;
  837.       }
  838.       
  839.       *cp = '\0';
  840.       startbyte = atoi(selstr+1);
  841.       oldcp = cp+1;
  842.  
  843.       cp = strchr(oldcp, '-');
  844.       
  845.       if (cp == NULL) {
  846.            Abortoutput(sockfd, "Range specifier error");
  847.            exit(-1);
  848.       }
  849.  
  850.       *cp = '\0';
  851.       endbyte = atoi(oldcp);
  852.       oldcp = cp + 1;
  853.       if (DEBUG)
  854.            fprintf(stderr, "Start: %d, End: %d  File: %s\n", startbyte, endbyte, oldcp);
  855.  
  856.       writestring(sockfd, "This section is from the document '");
  857.       writestring(sockfd, oldcp);
  858.       writestring(sockfd, "'.\r\n\r\n");
  859.       printfile(sockfd, oldcp, startbyte, endbyte);
  860.  
  861.       /*** Log it ***/
  862.       sprintf(logline, "retrieved range %d - %d of file %s", startbyte, endbyte, oldcp);
  863.       LOGGopher(sockfd, logline);
  864.       break;
  865.      }
  866.  
  867.      case 'f':
  868.       if (strncmp(selstr, "ftp:",4)==0){
  869.            SendFtpQuery(selstr+4);
  870.            TranslateResults(sockfd);
  871.            break;
  872.       }
  873.       sprintf(logline, "retrieved %s", selstr);
  874.       LOGGopher(sockfd, logline);
  875.       break;
  876.  
  877.      case 'e':
  878.       if (strncmp(selstr, "exec:", 5)==0) {
  879.            /* args are between colons */
  880.            char *args, *command;
  881.            
  882.            command = strrchr(selstr + 5, ':');
  883.            if ((command == NULL) || (command == selstr + 5))
  884.             break;
  885.            
  886.            args = selstr+5;
  887.            *command = '\0';
  888.            command++;
  889.            
  890.            EXECargs = selstr+5;
  891.  
  892.            printfile(sockfd, command, 0, -1);
  893.       }
  894.      case 'w':
  895.      {
  896.       if (strncmp(selstr, "waissrc:", 8) == 0) {
  897.            SearchRemoteWAIS(sockfd, selstr+8);
  898.            break;
  899.       }
  900.       else if (strncmp(selstr, "waisdocid:", 10) == 0) {
  901.            Fetchdocid(sockfd, selstr+10);
  902.            break;
  903.       }
  904.      }
  905.  
  906.  
  907.      default:
  908.       /*** Hmmm, must be an old link... Let's see if it exists ***/
  909.  
  910.       switch (isadir(selstr)) {
  911.       case -1:
  912.            /* no such file */
  913.            sprintf(inputline, "'%s' does not exist", selstr);
  914.            Abortoutput(sockfd, "File does not exist, or can't stat()");
  915.            break;
  916.  
  917.       case 0:
  918.            /* it's a file */
  919.            printfile(sockfd, selstr, 0, -1);
  920.            
  921.            /* Log it... */
  922.            strcpy(logline, "retrieved file ");
  923.            strcat(logline, selstr);
  924.            LOGGopher(sockfd, logline);
  925.  
  926.            break;
  927.  
  928.       case 1:
  929.            /* it's a directory */
  930.            listdir(sockfd, selstr);
  931.  
  932.            /* Log it */
  933.            strcpy(logline, "retrieved directory ");
  934.            strcat(logline, inputline);
  935.            LOGGopher(sockfd, logline);
  936.  
  937.            break;
  938.       }
  939.      }
  940.  
  941.      return(0);
  942. }
  943.  
  944. /*
  945.  * Cache timeout value.
  946.  *   If cache is less than secs seconds old, it's ok.
  947.  *   Otherwise, compare time of cache to dir and all files in dir and dir/.cap.
  948.  *   If cache is newest, it's ok, otherwise it must be rebuilt.
  949.  * 
  950.  * Not really great for big directories, but better in general for smaller
  951.  * directories..
  952.  */
  953.  
  954. boolean
  955. Cachetimedout(cache, secs, dir)
  956.   char *cache;
  957.   int secs;
  958.   char *dir;
  959. {
  960.      STATSTR       buf;
  961.      int           result;
  962.      time_t        now;
  963.      int           cachetime;
  964.      char          cappath[512];
  965.      DIR           *ZeDir;
  966.      struct dirent *dp;
  967.  
  968.      result = rstat(cache, &buf);
  969.  
  970.      if (result != 0)
  971.       return(-1);
  972.  
  973.      time(&now);
  974.      
  975.      if (DEBUG) 
  976.       printf("Cache now: %d, cache file: %d", now,buf.st_mtime);
  977.      
  978.      if ( now < (buf.st_mtime + secs))
  979.       return(FALSE);
  980.  
  981.           cachetime = buf.st_mtime;
  982.  
  983.      
  984.      /** Check the directory, see if it's been modified... **/
  985.      result = rstat(dir, &buf);
  986.  
  987.      if (result == 0 && cachetime < buf.st_mtime)
  988.       return(TRUE);
  989.      
  990.      if ((ZeDir = ropendir(dir)) == NULL)
  991.           return(TRUE);
  992.  
  993.      for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
  994.       result = rstat(dp->d_name, &buf);
  995.       if (result == 0 && cachetime < buf.st_mtime) {
  996.            closedir(ZeDir);
  997.            return(TRUE);
  998.       }
  999.      }
  1000.      closedir(ZeDir);
  1001.  
  1002.      sprintf(cappath, "%s/.cap", dir);
  1003.      if ((ZeDir = ropendir(cappath)) == NULL)
  1004.           return(FALSE);
  1005.      
  1006.      for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
  1007.       result = rstat(dp->d_name, &buf);
  1008.       if (result == 0 && cachetime < buf.st_mtime) {
  1009.            closedir(ZeDir);
  1010.            return(TRUE);
  1011.       }
  1012.      }
  1013.      closedir(ZeDir);
  1014.      
  1015.      return(FALSE);
  1016. }
  1017.  
  1018. /*
  1019.  * Returns true (1) for a directory
  1020.  *         false (0) for a file
  1021.  *         -1 for anything else
  1022.  */
  1023.  
  1024. boolean
  1025. isadir(path)
  1026.   char *path;
  1027. {
  1028.      STATSTR buf;
  1029.      int result;
  1030.  
  1031.      result = rstat(path, &buf);
  1032.  
  1033.      if (result != 0)
  1034.       return(-1);
  1035.      
  1036.      if (S_ISDIR(buf.st_mode)) {
  1037.       if (! access(path, F_OK))
  1038.            return(1);
  1039.       else
  1040.            return(-1);
  1041.      }
  1042.      else if (S_ISREG(buf.st_mode))
  1043.       return(0);
  1044.      else
  1045.       return(-1);
  1046. }
  1047.  
  1048.  
  1049. /*
  1050.  * This function tries to find out what type of file a pathname is.
  1051.  * It then fills in the VAR type variables ObjType & ServerPath with
  1052.  * corresponding info.
  1053.  */
  1054.  
  1055. Getfiletypes(newpath, filename, ObjType, ServerPath)
  1056.   char *newpath;
  1057.   char *filename;
  1058.   char **ObjType;
  1059.   char **ServerPath;
  1060. {
  1061.      boolean dirresult;
  1062.      int Zefilefd;
  1063.      static char Zebuf[64];
  1064.      char *cp;
  1065.      static char Selstr[512];
  1066.  
  1067.      
  1068.      if (ServerPath != NULL)         /* Don't overwrite existing path if any */
  1069.       *ServerPath = Selstr; 
  1070.  
  1071.  
  1072.      dirresult = isadir(filename);
  1073.  
  1074.      if (dirresult == -1) {             /** Symlink or Special **/
  1075.       *ObjType = "3";
  1076.       return;
  1077.      }
  1078.  
  1079.      if (dirresult == 1) {
  1080.       *ObjType = "1";
  1081.       *Selstr = '1';
  1082.       strcpy(Selstr +1, newpath);
  1083.       return;
  1084.      }
  1085.          
  1086.      
  1087.      else {          /** Some kind of data file.... */
  1088.  
  1089.       /** Macintosh HQX files **/
  1090.       
  1091.       if ((strcmp(filename+strlen(filename)-4, ".hqx")) == 0) {
  1092.            *ObjType = "4";
  1093.            *Selstr = '0';
  1094.            strcpy(Selstr + 1, newpath);
  1095.            return;
  1096.       }
  1097.  
  1098.       /** SGML files end in .html **/
  1099.  
  1100.       if ((strcmp(filename+strlen(filename)-5, ".html")) ==0) {
  1101.            *ObjType = "h";
  1102.            strcpy(Selstr, "GET /h");
  1103.            strcat(Selstr, newpath);
  1104.            return;
  1105.       }
  1106.  
  1107. #ifdef WAISSEARCH
  1108.       if ((strcmp(filename+strlen(filename)-4, ".src")) == 0) {
  1109.            *ObjType = "7";
  1110.            strcpy(Selstr, "waissrc:");
  1111.            strcat(Selstr, newpath);
  1112.            return;
  1113.       }
  1114. #endif
  1115.  
  1116.       else if ((strcmp((char*)filename+strlen(filename)-6,".tar.Z"))== 0){
  1117.            *ObjType = "9";
  1118.            *Selstr = '9';
  1119.            strcpy(Selstr + 1, newpath);
  1120.            return;
  1121.       }
  1122.  
  1123.       /*** Test and see if the thing exists... ***/
  1124.       
  1125.       if ((Zefilefd = ropen(filename, O_RDONLY)) < 0) {
  1126.            *ObjType = "3";
  1127.            return;
  1128.       }
  1129.       
  1130.       bzero(Zebuf, 64);
  1131.       read(Zefilefd, Zebuf, 64);
  1132.       close(Zefilefd);
  1133.       
  1134.       /*** Check the first few bytes for sound data ***/
  1135.       
  1136.       cp = Zebuf;
  1137.  
  1138.       if (*cp++ == '.' && *cp++ == 's' && *cp++ == 'n' && *cp++ == 'd') {
  1139.            *ObjType = "s";
  1140.            *Selstr = 's';
  1141.            strcpy(Selstr+1, newpath);
  1142.            
  1143.            return;
  1144.       }
  1145.  
  1146.       /*** Check and see if it's mailbox data ***/
  1147.       
  1148.       if (is_mail_from_line(Zebuf)==0) {
  1149.            *ObjType = "1";
  1150.            *Selstr = 'm';
  1151.            strcpy(Selstr+1, newpath);
  1152.  
  1153.            return;
  1154.       }
  1155.       
  1156.  
  1157.       /*** Check for uuencoding data ***/
  1158.  
  1159.       cp = Zebuf;
  1160.       
  1161.       if (*cp++ == 'b' && *cp++ == 'e' && *cp++ == 'g' &&
  1162.           *cp++ == 'i' && *cp++ == 'n')  {
  1163.            *ObjType = "6";
  1164.            *Selstr = '6';
  1165.            strcpy(Selstr+1, newpath);
  1166.            
  1167.            return;
  1168.       }
  1169.       
  1170.       /*** The default is a generic text file ***/
  1171.  
  1172.       *ObjType = "0";
  1173.       *Selstr = '0';
  1174.       strcpy(Selstr + 1, newpath);
  1175.       return;
  1176.      }
  1177.  
  1178.      /*** we shouldn't be able to get here..... ***/
  1179.      /*** but if you do, you won't have set *ObjType, so you'll
  1180.       be in trouble ***/
  1181.      *ObjType = "3";
  1182.      return;
  1183. }
  1184.  
  1185.  
  1186.  
  1187.  
  1188. /*
  1189. ** This function lists out what is in a particular directory.
  1190. ** it also outputs the contents of link files.
  1191. **
  1192. ** It also checks for the existance of a .cache file if caching is
  1193. ** turned on...
  1194. **
  1195. ** Ack is this ugly.
  1196. */
  1197.  
  1198. void
  1199. listdir(sockfd, pathname)
  1200.   int sockfd;
  1201.   char *pathname;
  1202. {
  1203.      DIR                   *ZeDir;
  1204.      FILE                  *DotFile;
  1205.      int                   i;
  1206.      char                  *cp, ch;
  1207.      static char           ZeObjType[3];
  1208.      char                  sidename[256];
  1209.      char                  filename[256];
  1210.      static char           newpath[512];
  1211.  
  1212.      FILE                  *SideFile;
  1213.      
  1214.      static GopherStruct   *Gopherp = NULL;
  1215.      char               *Typep, *Pathp, *cachefile;
  1216.      struct dirent  *dp;
  1217.  
  1218.      /*** Make our gopherstruct ****/
  1219.      if (Gopherp == NULL)
  1220.       Gopherp = GSnew();
  1221.  
  1222.      if (rchdir(pathname)<0) {
  1223.       Abortoutput(sockfd, "- Cannot access that directory");
  1224.           return;
  1225.      }
  1226.      
  1227.      if (UsingHTML)
  1228.       cachefile = ".cache.html";
  1229.      else
  1230.       cachefile = ".cache";
  1231.  
  1232.      if (Caching && Cachetimedout(cachefile, CACHE_TIME, ".")==FALSE) {
  1233.       /** Cache is still active, spit out the cache file 
  1234.           and get outta here..... **/
  1235.       printfile(sockfd, cachefile, 0, -1);
  1236.       return;
  1237.      }
  1238.  
  1239.      /** If we didn't cache then we have to use a sorting directory... **/
  1240.      SortDir = GDnew(64);
  1241.  
  1242.      /* open "." since we just moved there - makes it work when not
  1243.     chroot()ing and using relative paths */
  1244.      if ((ZeDir = ropendir(".")) == NULL) {
  1245.       Abortoutput(sockfd, "Cannot get that directory");
  1246.       return;
  1247.      }
  1248.  
  1249.      for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
  1250.  
  1251.           strcpy(newpath, pathname);
  1252.           if (newpath[strlen(newpath)-1] != '/')
  1253.                strcat(newpath, "/");
  1254.           strcat(newpath, dp->d_name);
  1255.  
  1256.       strcpy(sidename, "./.cap/");
  1257.       strcpy(filename, dp->d_name);
  1258.       strcat(sidename, dp->d_name);
  1259.       
  1260.       /** Only chew list out files that don't start with a dot **/
  1261.       /** or aren't named dev, usr, bin, etc, or core.         **/
  1262.  
  1263.       if (filename[0] == '.' && 
  1264.           isadir(filename)==0  &&
  1265.           strncmp(filename, ".cache", 6) !=0) {
  1266.            /*** This is a link file, let's process it ***/
  1267.            int linkfd;
  1268.  
  1269.            linkfd = uopen(filename, O_RDONLY);
  1270.  
  1271.            if (linkfd >0) {
  1272.             GDfromLink(SortDir, linkfd, Zehostname, GopherPort);
  1273.             close(linkfd);
  1274.            }
  1275.            
  1276.       }
  1277.  
  1278.       if ((filename[0] != '.')
  1279.           && strcmp(filename, "bin") != 0 && 
  1280.              strcmp(filename, "dev") != 0 &&
  1281.              strcmp(filename, "usr") != 0 &&
  1282.              strcmp(filename, "core")!= 0 &&
  1283.              strcmp(filename, "etc") != 0)   {
  1284.            
  1285.            /** Check to see if there's a set-aside file with more info ***/
  1286.            /** But first initialize the Gopherstruct **/
  1287.  
  1288.            GSinit(Gopherp);
  1289.  
  1290.            GSsetHost(Gopherp, Zehostname);
  1291.            GSsetPort(Gopherp, GopherPort);
  1292.            Typep = Pathp = NULL;
  1293.            
  1294.  
  1295.            Getfiletypes(newpath, filename, &Typep, &Pathp);
  1296.            if (*Typep =='3')
  1297.             continue;
  1298.            
  1299.            GSsetType(Gopherp, Typep[0]);
  1300.            GSsetPath(Gopherp, Pathp);
  1301.  
  1302.  
  1303.             if (GSgetTitle(Gopherp) == NULL) {
  1304.             /*** Check to see if we have a compressed file ***/
  1305.             
  1306.             if (strcmp(filename + strlen(filename) -2, ".Z") ==0 &&
  1307.             strcmp(filename + strlen(filename) -6, ".tar.Z") != 0)
  1308.              filename[strlen(filename) - 2] = '\0';
  1309.             
  1310.             GSsetTitle(Gopherp, filename);
  1311.            }
  1312.            else
  1313.             GSsetTitle(Gopherp, filename);
  1314.  
  1315.  
  1316.            if ((SideFile = rfopen(sidename, "r"))!=0) {
  1317.             if (DEBUG == TRUE)
  1318.              printf("Side file name: %s\n", sidename);
  1319.             Process_Side(SideFile, Gopherp);
  1320.            }
  1321.  
  1322.  
  1323.            /*** Add the entry to the directory ***/
  1324.   
  1325.            GDaddGS(SortDir, Gopherp);
  1326.  
  1327.       }
  1328.      }
  1329.      
  1330.      GDsort(SortDir);
  1331.  
  1332.      if (UsingHTML)  {
  1333.       int aboutfd;
  1334.  
  1335.       aboutfd = uopen(".about.html", O_RDONLY);
  1336.       if (aboutfd > 0) {
  1337.            while (readline(aboutfd, newpath, 512))
  1338.             writestring(sockfd, newpath);
  1339.            close(aboutfd);
  1340.       }
  1341.            
  1342.       GDtoNetHTML(SortDir, sockfd);
  1343.      }
  1344.      else
  1345.       GDtoNet(SortDir, sockfd);
  1346.  
  1347.      writestring(sockfd, ".\r\n");
  1348.  
  1349.      /*
  1350.       * Write out the cache... *After* we send out the data to the net.
  1351.       */
  1352.      if (Caching) {
  1353.       int cachefd;
  1354.  
  1355.       cachefd = uopen(cachefile, O_WRONLY|O_CREAT|O_TRUNC, 0755);
  1356.  
  1357.       if (cachefd != 0) {
  1358.            if (DEBUG) {
  1359.             printf("Caching directory...\n");
  1360.            }
  1361.            if (UsingHTML) {
  1362.             int aboutfd; 
  1363.  
  1364.             aboutfd = uopen(".about.html", O_RDONLY);
  1365.             if (aboutfd > 0) {
  1366.              while (readline(aboutfd, newpath, 512))
  1367.                   writestring(cachefd, newpath);
  1368.              close(aboutfd);
  1369.             }
  1370.             
  1371.             GDtoNetHTML(SortDir, cachefd);
  1372.            }
  1373.            else
  1374.             GDtoNet(SortDir, cachefd);
  1375.  
  1376.            close(cachefd);
  1377.       }
  1378.      }
  1379.  
  1380.      closedir(ZeDir);
  1381. }
  1382.  
  1383.  
  1384. /*
  1385.  * This processes a file containing any subset of
  1386.  * Type, Name, Path, Port or Host, and returns pointers to the
  1387.  * overriding data that it finds.
  1388.  *
  1389.  * The caller may choose to initialise the pointers - so we don't
  1390.  * touch them unless we find an over-ride.
  1391.  */
  1392.  
  1393. Process_Side(sidefile, Gopherp)
  1394.   FILE *sidefile;
  1395.   GopherObj *Gopherp;
  1396. {
  1397.      char inputline[MAXLINE];
  1398.      static char ItemType[3];
  1399.      static char ItemName[255];
  1400.      static char Path[255];
  1401.      static char Host[64];
  1402.      static char Port[10];
  1403.      char *cp;
  1404.  
  1405.  
  1406.      inputline[0] = '\0';
  1407.  
  1408.      for (;;) {
  1409.       for (;;) {
  1410.            cp = fgets(inputline, 1024, sidefile);
  1411.            if (inputline[0] != '#' || cp == NULL)
  1412.             break;
  1413.       }
  1414.       
  1415.       /*** Test for EOF ***/
  1416.       if (cp==NULL)
  1417.            break;
  1418.       
  1419.       ZapCRLF(inputline);  /* should zap tabs as well! */
  1420.  
  1421.       /*** Test for the various field values. **/
  1422.       
  1423.       if (strncmp(inputline, "Type=", 5)==0) {
  1424.            GSsetType(Gopherp, inputline[5]);
  1425.            if (inputline[5] == '7') {
  1426.             /*** Might as well set the path too... ***/
  1427.             *(GSgetPath(Gopherp)) = '7';
  1428.            }
  1429.       }
  1430.  
  1431.       else if (strncmp(inputline, "Name=", 5)==0) {
  1432.            GSsetTitle(Gopherp, inputline+5);
  1433.       }
  1434.  
  1435.       else if (strncmp(inputline, "Host=", 5)==0) {
  1436.            GSsetHost(Gopherp, inputline+5);
  1437.       }
  1438.  
  1439.       else if (strncmp(inputline, "Port=", 5)==0) {
  1440.            GSsetPort(Gopherp, atoi(inputline+5));
  1441.       }
  1442.  
  1443.       else if (strncmp(inputline, "Path=", 5)==0) {
  1444.            GSsetPath(Gopherp, inputline+5);
  1445.       }
  1446.  
  1447.       else if (strncmp(inputline, "Numb=", 5)==0) {
  1448.            GSsetNum(Gopherp, atoi(inputline+5));
  1449.       }
  1450.  
  1451.       else if (strncmp(inputline, "Name=", 5)==0) {
  1452.            GSsetTitle(Gopherp, inputline+5);
  1453.       }
  1454.  
  1455.      }
  1456.  
  1457.      fclose(sidefile);
  1458. }
  1459.  
  1460.  
  1461.  
  1462.  
  1463.  
  1464. /*
  1465. ** This function opens the specified file, starts a zcat if needed,
  1466. ** and barfs the file across the socket.
  1467. **
  1468. ** It now also checks and sees if access is allowed
  1469. **
  1470. **
  1471. */
  1472.  
  1473. void
  1474. printfile(sockfd, pathname, startbyte, endbyte)
  1475.   int sockfd;
  1476.   char *pathname;
  1477.   int startbyte, endbyte;
  1478. {
  1479.      FILE *ZeFile;
  1480.      char inputline[512];
  1481.      int i;
  1482.      char Zcatcommand[256];
  1483.      char *cp;
  1484.  
  1485.  
  1486.      /*
  1487.       * This chdir is unnecssary, since we have not gone anywhere since
  1488.       * the chroot.
  1489.       */
  1490.      /* rchdir("/"); */
  1491.  
  1492.      /*** Check and see if the peer has permissions to read files ***/
  1493.      
  1494.      if (UsingHTML) {
  1495.       writestring(sockfd, "<XMP>\r\n");
  1496.      }
  1497.      
  1498.      if (Can_Read(sockfd) == FALSE) {
  1499.       if (writestring(sockfd, BUMMERSTR) <0)
  1500.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1501.       writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
  1502.       close(sockfd);
  1503.       return;
  1504.      }
  1505.  
  1506.      if ( (ZeFile = rfopen(pathname, "r")) == NULL) {
  1507.       /*
  1508.        * The specified file does not exist
  1509.        */
  1510.       char notexistline[256];
  1511.       sprintf(notexistline, "'%s' does not exist!!", pathname);
  1512.       Abortoutput(sockfd, notexistline);
  1513.  
  1514.       return;
  1515.      }
  1516.  
  1517.      if (startbyte != 0)
  1518.       fseek(ZeFile, startbyte, 0);
  1519.  
  1520.      {
  1521.       FILE *pp;
  1522.       if (pp = specialfile(ZeFile, pathname)) {
  1523.            fclose(ZeFile);
  1524.            ZeFile = pp;
  1525.       }
  1526.      }
  1527.  
  1528.  
  1529.      while (fgets(inputline, MAXLINE, ZeFile) != NULL) {
  1530.  
  1531.       ZapCRLF(inputline);
  1532.       if (writestring(sockfd, inputline) <0)
  1533.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1534.       if (writestring(sockfd, "\r\n"))
  1535.            LOGGopher(sockfd, "Client went away"), exit(-1);
  1536.  
  1537.       if (endbyte >0) {
  1538.            if (ftell(ZeFile) >= endbyte)
  1539.             break;
  1540.       }
  1541.      }
  1542.  
  1543.      Specialclose(ZeFile);
  1544.  
  1545.      if (UsingHTML) {
  1546.       writestring(sockfd, "</XMP>\r\n");
  1547.      }
  1548.  
  1549.      if (writestring(sockfd, ".\r\n")<0)
  1550.       LOGGopher(sockfd, "Client went away"), exit(-1);
  1551. }
  1552.  
  1553.  
  1554. #define BUFSIZE 1400  /* A pretty good value for ethernet */
  1555.  
  1556. void
  1557. echosound(sockfd, filename)
  1558.   int sockfd;
  1559.   char *filename;
  1560. {
  1561.  
  1562.      FILE *sndfile;
  1563.      unsigned char in[BUFSIZE];
  1564.      register int j;
  1565.      int gotbytes;
  1566.  
  1567.      if (strcmp(filename, "-") == 0) {
  1568.       /*** Do some live digitization!! **/
  1569.       sndfile = popen("record -", "r");
  1570.      }
  1571.      else
  1572.       sndfile = rfopen(filename, "r");
  1573.  
  1574.      while(1) {
  1575.       gotbytes = fread(in, 1, BUFSIZE, sndfile);
  1576.       
  1577.       if (gotbytes == 0)
  1578.            break;       /*** end of file or error... ***/
  1579.  
  1580.           j = writen(sockfd, in, gotbytes);
  1581.  
  1582.       if (j == 0)
  1583.            break;       /*** yep another error condition ***/
  1584.  
  1585.      }
  1586. }
  1587.  
  1588.